use std::sync::{mpsc,Arc};
use std::thread;


// 创建线程数量
const THREAD_COUNT :i32 = 2;

static mut  VAR:i32=32;

fn main() {
    // 创建线程
    let new_thread = thread::spawn(move || {
        println!("创建线程");
    });

    //等待新建线程执行完成
    new_thread.join().unwrap();

    //创建一个自定义线程
    let new_thread_result = thread::Builder::new()
        .name("thread".to_string())
        .stack_size(4 * 1024 * 1024)
        .spawn(move || println!("创建第二个线程"));

    // 等待新创建的线程执行完成
    new_thread_result.unwrap().join().unwrap();

    // 消息传递（channel）

    // channel可以将一个线程的消息传递到另一个线程,通道两端分别是发送者和接收者，发送者负责从一个线程发送消息，接收者则在另一个线程中接收该消息
    // 创建一个通道
    let (tx, rx): (mpsc::Sender<i32>, mpsc::Receiver<i32>) = mpsc::channel();

    //创建线程用于发送消息
    thread::spawn(move || {
        tx.send(1).unwrap();
    });
    
    // 在主线程中接收子线程发送的消息并输出
    println!("receive {}", rx.recv().unwrap());

    //消息类型
    // 不是所有类型都是支持传递的 （!send）
    // Send是一个默认应用到所有Rust已存在类的trait，所以我们用!Send显式标明该类没有实现Send
    // 如果一个类型是Send，则表明它可以在线程间安全的转移所有权(ownership)，当所有权从一个线程转移到另一个线程后，同一时间就只会存在一个线程能访问它，这样就避免了数据竞争，从而做到线程安全
    // 如果自定义类的所有字段都是Send，那么这个自定义类也是Send。 反之，如果有一个字段是!Send，那么这个自定义类也是!Send
    // 对于不是Send的情况（!Send），大致分为两类：
    //   原始指针，包括*mut T和*const T，因为不同线程通过指针都可以访问数据，从而可能引发线程安全问题。
    //   Rc和Weak也不是，因为引用计数会被共享，但是并没有做并发控制

    // 异步通道
    let (tx_async,rx_async) :(mpsc::Sender<i32>,mpsc::Receiver<i32>)=mpsc::channel();

    for id in 0..THREAD_COUNT {
        // 注意Sender是可以clone的，这样就可以支持多个发送者
        let thread_tx = tx_async.clone();
        thread::spawn(move || {
            // 发送一个消息，此处是数字id
            thread_tx.send(id + 1).unwrap();
            println!("send {}", id + 1);
        });
    }

    thread::sleep_ms(2000);
    println!("weak up");

    for _ in 0..THREAD_COUNT{
        println!("receive {}", rx_async.recv().unwrap());
    }

    // 线程是不阻塞的
    // 通道是可以同时支持多个发送者的，通过clone,可以有多个发送者但只能有一个接收者n：1的模式
    // 消息发送和接收顺序是一致的，先进先出


    // 同步
    // 创建同步通道
    let (tx_tb,rx_tb):(mpsc::SyncSender<i32>, mpsc::Receiver<i32>) = mpsc::sync_channel(0);
    // 创建线程用于发送消息
    let new_thread_tb = thread::spawn(move || {
        // 发送一个消息，此处是数字id
        println!("before send");
        tx_tb.send(1).unwrap();
        println!("after send");
    });

    
    println!("before sleep");
    thread::sleep_ms(5000);
    println!("after sleep");
    // 在主线程中接收子线程发送的消息并输出
    println!("receive {}", rx_tb.recv().unwrap());
    
    new_thread_tb.join().unwrap();

    // 同步和异步的区别：
    // 同步通道是需要指定缓存的消息个数的，但需要注意的是，最小可能是0，表示没有缓存
    // 发送者是会被阻塞的，当通道的缓存队列不能再缓存消息时，发送者发送消息会被阻塞


    // 共享内存
    // static 其生命周期是整个应用程序，并且在内存中某个固定地址处只存在一份实例。所有线程都能够访问到它
    // 创建一个新线程
    let new_thread_gx = thread::spawn(move|| {
       
        // 修改
        unsafe{
            println!("static value in new thread: {}", VAR);
            VAR+=1;
        }
    });

    new_thread_gx.join().unwrap();
    unsafe{
        println!(" static value {}",VAR)
    }
    // 堆

    let var:Arc<i32> =Arc::new(5);
    let share_var=var.clone();

    // 创建一个新的线程
    let thread_d=thread::spawn(move|| {
        println!("share value in new thread: {}, address: {:p}", share_var, &*share_var);
    });

    thread_d.join().unwrap();

    println!("share value in main thread: {}, address: {:p}", var, &*var);
}
